package com.moon.game.service;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.google.gson.Gson;
import com.moon.game.cache.LRUCache;
import com.moon.game.clazz.PlayerItemsProto.PlayerItems.PlayerItem;
import com.moon.game.command.RequestSession;
import com.moon.game.constants.Constants;
import com.moon.game.exception.GException;
import com.moon.game.manager.ItemMG;
import com.moon.game.manager.LevelExpMG;
import com.moon.game.manager.PlayerMG;
import com.moon.game.profile.ProfileService;
import com.moon.game.resource.model.Item;
import com.moon.game.util.Utils;
import com.moon.game.vos.PlayerVo;
import com.moon.game.vos.PlayerVo.Skill;
import com.moon.game.vos.PlayerVo.UsedItem;

public class PlayerService {
	private static final Logger log = Logger.getLogger(PlayerService.class);
	private static final Logger flowLog = Logger.getLogger(Constants.LOG_FLOW);
	private static final Logger profileLog = Logger.getLogger(Constants.LOG_PROFILE);
	private static LRUCache<String, HashMap<String, PlayerVo>> playerCache = new LRUCache<String, HashMap<String, PlayerVo>>(500);
	
	public static PlayerVo doTran2Vo(Object o) {
		if (o instanceof PlayerVo) {
			return (PlayerVo)o;
		}else {
			return new Gson().fromJson(new Gson().toJson(o), PlayerVo.class);
		}
	}
	
	/**
	 * 发送查询player请求
	 * 
	 * @param sid
	 * @param req
	 * @param player
	 */
	public static PlayerVo doGetPlayer(String sid,String playerId) {
		
		try {
			if (playerId == null) {
				return null;
			}
			PlayerVo playerVo = PlayerMG.instance.getPlayer(playerId);
			if (playerVo != null) {
				return playerVo;
			}
			HashMap<String, PlayerVo> playerMap = playerCache.get(sid);
			if (playerMap == null) {
				playerMap = ProfileService.getPlayerFromDB(sid);
			}
			if (playerMap != null) {
				for (Map.Entry<String, PlayerVo> entry : playerMap.entrySet()) {
					if (playerId.equals(entry.getKey())) {
						return doTran2Vo(entry.getValue());
					}
				}
			}
		} catch (GException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 获取帐号下的人物列表
	 * 
	 * @param sid
	 * @return
	 */
	public static HashMap<String, PlayerVo> doGetPlayerMap(String sid) {
		
		try {
			HashMap<String, PlayerVo> playerMap = playerCache.get(sid);
			if (playerMap == null) {
				playerMap = ProfileService.getPlayerFromDB(sid);
			}
			return playerMap;
		} catch (GException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 更新玩家
	 * 
	 * @param playerId
	 * @param newPlayer
	 */
	public static void doUpdatePlayer(String sid, String playerId, PlayerVo newPlayer) {
		if (newPlayer == null||newPlayer.getId() == null||"".equals(newPlayer.getId())||newPlayer.getLevel()==0){
			profileLog.error("update player error, new player is null:"+playerId);
			return;
		}
		if (!playerId.equals(newPlayer.getId())) {
			profileLog.error("update player error, diffent player:"+playerId+"|"+newPlayer.getId());
			return;
		}
		try {
			updatePlayerLog(newPlayer);
			HashMap<String, PlayerVo> playerMap = playerCache.get(sid);
			if (playerMap == null) {
				playerMap = ProfileService.getPlayerFromDB(sid);
				if (playerMap == null) {
					playerMap = new HashMap<String, PlayerVo>();
				}
			}
			playerMap.put(playerId, newPlayer);
			playerCache.set(sid, playerMap);
			ProfileService.savePlayer2DB(sid, playerMap);
			profileLog.debug("update player:" + playerId + " success!");
		} catch (GException e) {
			profileLog.error("update player error,can't save player:" + playerId);
			e.printStackTrace();
		}
	}
	
	/**
	 * 更新人物日志
	 * 
	 * @param newPlayer
	 */
	public static void updatePlayerLog(PlayerVo newPlayer) {
		StringBuffer sb = new StringBuffer();
		sb.append(newPlayer.getId() + "|");
		sb.append(newPlayer.getPasswd() + "|");
		sb.append(newPlayer.getLevel() + "|");
		sb.append(newPlayer.getSex() + "|");
		sb.append(newPlayer.getHp() + "|");
		sb.append(newPlayer.getMp() + "|");
		sb.append(newPlayer.getExp() + "|");
		sb.append(newPlayer.getMoney() + "|");
		sb.append(newPlayer.getGold() + "|");
		sb.append(newPlayer.getMaxRoom() + "|");
		sb.append(newPlayer.getLocation() + "|");
		sb.append(newPlayer.getBurden() + "|");
		List<Skill> skills = newPlayer.getSkill();
		if (skills != null) {
			sb.append("skills:");
			StringBuffer skillBuffer = new StringBuffer();
			for (Skill skill : skills) {
				skillBuffer.append(skill.getSkillId() + "-");
			}
			sb.append(skillBuffer.toString() + "|");
		}
		profileLog.debug("player details:" + sb.toString());
	}
	
	/**
	 * 创建新玩家入库
	 * 
	 * @param player
	 */
	public static void doCreatePlayer(PlayerVo player) {
		if (player == null) {
			profileLog.error("create player is null!");
			return;
		}
		if (player.getId() == null || "".equals(player.getId())) {
			profileLog.error("create playerid is blank");
			return;
		}
		try {
			HashMap<String, PlayerVo> playerMap = playerCache.get(player.getSid());
			if (playerMap == null) {
				playerMap = ProfileService.getPlayerFromDB(player.getSid());
				if (playerMap == null) {
					playerMap = new HashMap<String, PlayerVo>();
				}
			}
			playerMap.put(player.getId(), player);
			playerCache.set(player.getSid(), playerMap);
			PlayerMG.instance.getOnlineMap().put(player.getId(), player);
			ProfileService.savePlayer2DB(player.getSid(), playerMap);
			profileLog.debug("create player:" + player.getId() + " success!");
		} catch (GException e) {
			profileLog.error("create player error" + player.getId());
			e.printStackTrace();
		}
	}
	
	/**
	 *  流水日志
	 * 
	 * @param reqSession
	 */
	public static void logFlow(RequestSession reqSession) {
		StringBuffer flowbBuffer = new StringBuffer();
		if (reqSession.getPlayerId() == null) {
			flowbBuffer.append(reqSession.getSid() + "is logining!");
		}else {
			PlayerVo player = PlayerMG.instance.getPlayer(reqSession.getPlayerId());
			if (player != null) {
				//TODO:记录流水日志详细信息
			}
		}
		flowLog.info(flowbBuffer.toString());
	}
	
	/**
	 * 给指定玩家加经验
	 * 
	 * @param playerId
	 * @param exp
	 */
	public static void doAddExp(String sid, String playerId, int exp) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if (player == null) {
			log.error("find player err,there is null[" + playerId + "]of this playerId");
		}
		if (exp < 0) {
			exp = player.getExp() + exp > 0 ? exp : -player.getExp();
		}
		if (player.getLevel() >= Constants.PLAYER_MAX_LEVEL) {
			exp = 0;
		}
		if (exp == 0) {
			return;
		}
		player.setExp(player.getExp() + exp);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
	}
	
	/**
	 * 给指定玩家加碎银
	 * 
	 * @param playerId
	 * @param money
	 */
	public static boolean doAddMoney(String sid, String playerId, int money) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if (player == null) {
			log.error("find player err,there is null[" + playerId + "]of this playerId");
			return false;
		}
		if (money == 0) {
			return true;
		}
		player.setMoney(player.getMoney() + money);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
		return true;
	}
	
	/**
	 * 给指定玩家加碎银
	 * 
	 * @param playerId
	 * @param money
	 */
	public static boolean doAddMoney(PlayerVo player, int money) {
		if (player == null) {
			return false;
		}
		if (money == 0) {
			return true;
		}
		player.setMoney(player.getMoney() + money);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
		return true;
	}
	
	/**
	 * 扣除指定玩家的碎银
	 * 
	 * @param playerId
	 * @param money
	 * @return false:扣除失败，碎银不足;true:扣除成功
	 */
	public static boolean minusMoney(String sid, String playerId, int money) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if(player.getMoney() < money) {
			return false;
		}else {
			doAddMoney(sid, playerId, -money);
			return true;
		}
	}
	
	/**
	 * 检查指定玩家的碎银是否足够【不扣碎银】
	 * 
	 * @param playerId
	 * @param money
	 * @return false:碎银不足;true:足够
	 */
	public static boolean checkMoney(String sid, String playerId, int money) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if(player.getMoney() < money) {
			return false;
		}else {
			return true;
		}
	}
	
	/**
	 * 给指定玩家加金币
	 * 
	 * @param playerId
	 * @param gold
	 */
	public static boolean doAddGold(String sid, String playerId, int gold) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if (player == null) {
			log.error("find player err,there is null[" + playerId + "]of this playerId");
			return false;
		}
		if (gold == 0) {
			return true;
		}
		player.setGold(player.getGold() + gold);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
		return true;
	}
	
	/**
	 * 玩家加钱
	 * 
	 * @param player
	 * @param gold
	 * @return
	 */
	public static boolean doAddGold(PlayerVo player, int gold) {
		if (player == null) {
			return false;
		}
		if (gold == 0) {
			return true;
		}
		player.setGold(player.getGold() + gold);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
		return true;
	}
	
	/**
	 * 扣除指定玩家的金币
	 * 
	 * @param playerId
	 * @param gold
	 * @return false:扣除失败，碎银不足;true:扣除成功
	 */
	public static boolean minusGold(String sid, String playerId, int gold) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if(player.getGold() < gold) {
			return false;
		}else {
			doAddGold(sid, playerId, -gold);
			return true;
		}
	}
	
	/**
	 * 检查指定玩家的金币是否足够【不扣金币】
	 * 
	 * @param playerId
	 * @param money
	 * @return false:金币不足;true:金币足够
	 */
	public static boolean checkGold(String sid, String playerId, int gold) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if(player.getGold() < gold) {
			return false;
		}else {
			return true;
		}
	}
	
	/**
	 * 增加hp(+加血-减血)
	 * 
	 * @param playerId
	 * @param hp
	 */
	public static void doAddHp(String sid, String playerId, int hp) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if (player == null) {
			log.error("find player err,there is null[" + playerId + "]of this playerId");
		}
		if (hp > 0) {
			hp = player.getCurHp() + hp > player.getHp() ? player.getHp() : player.getCurHp() + hp;
		}else {
			hp = player.getCurHp() + hp > 0 ? player.getCurHp() + hp : 0;
		}
		player.setCurHp(hp);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
	}
	
	/**
	 * 增加mp
	 * 
	 * @param playerId
	 * @param mp
	 */
	public static void doAddMp(String sid, String playerId, int mp) {
		PlayerVo player = doGetPlayer(sid, playerId);
		if (player == null) {
			log.error("find player err,there is null[" + playerId + "]of this playerId");
		}
		if (mp > 0) {
			mp = player.getCurMp() + mp > player.getMp() ? player.getMp() : player.getCurMp() + mp;
		}else {
			mp = player.getCurMp() + mp > 0 ? player.getCurMp() + mp : 0;
		}
		player.setCurMp(mp);
//		UpdatePlayerThread.addSyncPlayerMap(player);
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
	}
	
	
	/**
	 * 穿装备(本游戏定义武器，头，手，身，脚分别只能装备一个道具，position为1，2，3，4，5)
	 * 
	 * @return -1表示装备的位置已经有道具了，-2表示要装备的道具是坏的,-3表示要装备的道具持久太低,0表示装备成功
	 */
	public static int wearTheEquip(PlayerVo player, PlayerItem playerItem) {
		if (playerItem.getBroken()) {
			return -2;
		}
		if (playerItem.getCurEndure() <= 0) {
			return -3;
		}
		List<UsedItem> usedItems = player.getUsedItem();
		List<PlayerItem> playerItems = PlayerItemService.getPlayerItems(player.getId());
		if (playerItems != null) {
			for (PlayerItem item : playerItems) {
				Item oldItem = ItemMG.instance.getItem(item.getItemId());
				if (item.getIsUse() && (oldItem.getPosition().intValue() == ItemMG.instance.getItem(playerItem.getItemId()).getPosition().intValue())) {
					return -1;
				}
			}
		}
		UsedItem usedItem = new UsedItem();
		playerItemTransUseItem(usedItem, playerItem);
		if (usedItems == null) {
			usedItems = new ArrayList<PlayerVo.UsedItem>();
		}
		usedItems.add(usedItem);
		player.setUsedItem(usedItems);
		return 0;
	}
	
	
	public static void playerItemTransUseItem(UsedItem usedItem, PlayerItem playerItem) {
		usedItem.setAppendId(playerItem.getGemList());
		usedItem.setId(playerItem.getPlayerItemId());
		usedItem.setCurrEndure(playerItem.getCurEndure());
		usedItem.setImproveLevel(playerItem.getImproveLevel());
		usedItem.setItemId(playerItem.getItemId());
		usedItem.setPropertyId(playerItem.getPropertyIdsList());
		usedItem.setAttackColdMax(playerItem.getAttackColdMax());
		usedItem.setAttackColdMin(playerItem.getAttackColdMin());
		usedItem.setAttackHotMax(playerItem.getAttackHotMax());
		usedItem.setAttackHotMin(playerItem.getAttackHotMin());
		usedItem.setDefenseColdMax(playerItem.getDefenseColdMax());
		usedItem.setDefenseColdMin(playerItem.getDefenseColdMin());
		usedItem.setDefenseHotMax(playerItem.getDefenseHotMax());
		usedItem.setDefenseHotMin(playerItem.getDefenseHotMin());
		usedItem.setNeedCharmValue(playerItem.getNeedCharmValue());
	}
	
	/**
	 * 升级指定玩家
	 * 
	 * @param player
	 * @return -1表示已经达到最大等级，-2经验不够升级，0升级成功
	 */
	public static int doUpgradeLevel(PlayerVo player,StringBuffer info) {
		if (player.getLevel() >= Constants.PLAYER_MAX_LEVEL) {
			log.debug("[" + player.getId() + "]is reach max level:" + player.getLevel());
			return -1;
		}
		
		int upgradeExp = LevelExpMG.instance.getLevelForExp(player.getLevel());
		if (player.getExp() < upgradeExp) {
			log.debug("[" + player.getId() + "]lack of exp to upgrade to" + (player.getLevel() + 1));
			return -2;
		}
		
		player.setLevel(player.getLevel() + 1);
		info.append("恭喜你升级到" + player.getLevel() + "(LV)<br/>");
		player.setExp(player.getExp() - upgradeExp);
		addValue(player,info);
		player.setCurHp(player.getHp());
		player.setCurMp(player.getMp());
		PlayerVo newPlayer = new PlayerVo();
		Utils.copyProperties(newPlayer, player);
		log.debug("[" + player.getId() + "]start upgrade to" + (player.getLevel() + 1));
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), newPlayer);
		log.debug("[" + player.getId() + "]upgrade to" + (player.getLevel() + 1) + "success!");
		return 0;
	}
	
	
	
	/**
	 * 每升5级增加本身属性
	 * 
	 * @param player
	 */
	private static void addValue(PlayerVo player,StringBuffer info) {
		if (player.getLevel() % 5 != 0) {
			info.append("气血增加：" + 5 + "<br/>");
			player.setHp(player.getHp() + 5);
			info.append("魔法增加：" + 2 + "<br/>");
			player.setMp(player.getMp() + 2);
			return;
		}
		info.append("气血增加：" + 20 + "<br/>");
		player.setHp(player.getHp() + 20);
		info.append("魔法增加：" + 10 + "<br/>");
		player.setMp(player.getMp() + 10);
		info.append("天赋寒攻增加：" + (doAdd(player.getAttackCold()) - player.getAttackCold()) + "<br/>");
		player.setAttackCold(doAdd(player.getAttackCold()));
		info.append("天赋炎攻增加：" + (doAdd(player.getAttackHot()) - player.getAttackHot()) + "<br/>");
		player.setAttackHot(doAdd(player.getAttackHot()));
		info.append("天赋寒防增加：" + (doAdd(player.getDefenseCold()) - player.getDefenseCold()) + "<br/>");
		player.setDefenseCold(doAdd(player.getDefenseCold()));
		info.append("天赋炎防增加：" + (doAdd(player.getDefenseHot()) - player.getDefenseHot()) + "<br/>");
		player.setDefenseHot(doAdd(player.getDefenseHot()));
		if (player.getLevel() <= 50) {
			//等级超过51级最大行囊和负重不再随等级增加而增加
			player.setMaxRoom(player.getMaxRoom() + 25);
			info.append("行囊空间增加：" + 25 + "<br/>");
			player.setBurden(player.getBurden() + 10);
			info.append("负重增加：" + 10 + "<br/>");
		}
		player.setCharmValue(player.getCharmValue() + 1);
		info.append("魅力增加：" + 1 + "<br/>");
	}
	private static int doAdd(int value) {
		return (int) (value * (1 + 0.4));
	}
	
}
